/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cs575.coresystem;

import cs575.dbentities.Session;
import cs575.dbentities.User;
import cs575.dbentities.Task;
import cs575.dbentities.GroupEx;
import cs575.dbentities.TaskAssign;
import cs575.dbentities.TaskAssignPK;
import cs575.dbentities.TaskUser;
import cs575.dbentities.TaskUserPK;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

/**
 *
 * @author bms
 */
public class TaskManagerE {

    private EntityManager em;

    public TaskManagerE() {
        this.em = null;
    }

    public TaskManagerE(EntityManager em) {
        this.em = em;
    }

    /**
     * Create a task
     * 
     * @param userId
     * @param taskName
     * @param taskDescription
     * @param dueDate
     * @param group
     * @return Task - newly created task or null
     */
    public Task createTask(int userId, String taskName, String taskDescription, String dueDate, GroupEx group) {
        EntityTransaction trans = em.getTransaction();
        trans.begin();

        Task newTask = null;
        Boolean result = false;

        try {
            newTask = new Task(taskName, taskDescription, dueDate, 1, group);
            result = storeTask(newTask);

            if (result) {
                Boolean read = true;
                Boolean edit = true;
                Boolean delete = true;
                Boolean setPerm = true;
                Boolean complete = true;
                TaskUser tu = new TaskUser(new TaskUserPK(newTask.getTaskId(), userId), read, edit, delete, setPerm, complete);

                // Check if there is a TaskUser entry already
                if ((em.find(TaskUser.class, new TaskUserPK(newTask.getTaskId(), userId))) == null) {
                    result = storeTaskUser(tu);
                }
            }

        } catch (DBStoringException ex) {
            Accounting.warning(TaskManagerE.class.getName(), ex.getMessage());
        } finally {
            if (result) {
                trans.commit();
            } else {
                trans.rollback();
            }
        }
        return newTask;
    }

    /**
     * Stores all Task entries
     * 
     * @param task - Task
     * @return 
     */
    public boolean storeTask(Task task) throws DBStoringException {
        boolean result = false;

        try {
            em.persist(task);
            result = true;
        } catch (Exception e) {
            throw new DBStoringException("storeTask: Failed!");
        }

        return result;
    }

    /**
     * Stores all TaskAssignment entries
     * 
     * @param task - Task
     * @return 
     */
    public boolean storeTaskAssignment(TaskAssign ta) throws DBStoringException {
        boolean result = false;

        try {
            em.persist(ta);
            result = true;
        } catch (Exception e) {
            throw new DBStoringException("storeTaskAssignment: Failed!");
        }

        return result;
    }

    /**
     * Stores all TaskUser entries
     * 
     * @param tu
     * @return
     * @throws DBStoringException 
     */
    public boolean storeTaskUser(TaskUser tu) throws DBStoringException {
        boolean result = false;

        try {
            em.persist(tu);
            result = true;
        } catch (Exception e) {
            throw new DBStoringException("storeTaskAssignment: Failed!");
        }

        return result;
    }

    /**
     * 
     * @param taskId
     * @return 
     */
    public Task retrieveTask(int taskId) {
        Task task = em.find(Task.class, taskId);
        return task;
    }

    /**
     * 
     * @param task
     * @return Boolean
     * @throws DBStoringException 
     */
    public boolean editTask(Task task) {
        boolean result = false;
        EntityTransaction trans = em.getTransaction();
        try {
            trans.begin();
            Task taskX = em.find(Task.class, task.getTaskId());

            if (taskX != null) {
                taskX.setTaskName(task.getTaskName());
                taskX.setTaskDescription(task.getTaskDescription());
                taskX.setDueDate(task.getDueDate());
                taskX.setStatus(task.getStatus());
                result = storeTask(taskX);
            }
        } catch (DBStoringException ex) {
            Accounting.warning(TaskManagerE.class.getName(), ex.getMessage());
        } finally {
            if (result) {
                trans.commit();
            } else {
                trans.rollback();
            }
        }

        return result;
    }

    /**
     * This methods loads and removes a given task based on the task id
     * 
     * @param task
     * @return
     * @throws DBStoringException 
     */
    public boolean deleteTask(Task task) {
        boolean result = false;
        EntityTransaction trans = em.getTransaction();
        try {
            trans.begin();
            // Load the task first
            Task newTask = em.getReference(Task.class, task.getTaskId());
            //Task newTask = this.retrieveTask(taskId);
            // Delete the entity
            if (newTask != null) {
                em.remove(newTask);
                result = true;
            }
        } catch (Exception ex) {
            Accounting.warning(TaskManagerE.class.getName(), ex.getMessage());
        } finally {
            if (result) {
                trans.commit();
            } else {
                trans.rollback();
            }
        }
        return result;
    }

    /**
     * 
     * @param task
     * @param soucUser
     * @param destUser
     * @return Boolean
     * @throws DBStoringException 
     */
    public Boolean assignTask(Task task, User sourceUser, User destUser) {
        boolean result = false;
        EntityTransaction trans = em.getTransaction();
        try {
            trans.begin();

            TaskAssign ta = new TaskAssign(task.getTaskId(), sourceUser.getUserId(), destUser.getUserId());
            if ((em.find(TaskAssign.class, ta.getTaskAssignPK())) == null) {
                ta.setComment("");
                ta.setIsApproved(false);
                ta.setIsReturned(false);
                result = storeTaskAssignment(ta);
            }
        } catch (DBStoringException ex) {
            Accounting.warning(TaskManagerE.class.getName(), ex.getMessage());
        } finally {
            if (result) {
                trans.commit();
            } else {
                trans.rollback();
            }
        }

        return result;
    }

    /**
     * 
     * @param taskId
     * @param user
     * @return
     * @throws DBStoringException 
     */
    public boolean completeTask(int taskId) {
        boolean result = false;
        EntityTransaction trans = em.getTransaction();
        try {
            trans.begin();
            Task task = this.retrieveTask(taskId);
            task.setStatus(task.Completed);
            result = storeTask(task);
        } catch (DBStoringException ex) {
            Accounting.warning(TaskManagerE.class.getName(), ex.getMessage());
        } finally {
            if (result) {
                trans.commit();
            } else {
                trans.rollback();
            }
        }
        return result;
    }

    /**
     * Accepts a task and creates a TaskUser entry, which keeps track of the user permission on the new task
     * 
     * @param taskId
     * @param userId
     * @return 
     */
    public boolean acceptTask(int taskId, int userId) {
        boolean result = false;
        EntityTransaction trans = em.getTransaction();
        try {
            trans.begin();
            Boolean read = true;
            Boolean edit = true;
            Boolean delete = false;
            Boolean setPerm = false;
            Boolean complete = true;
            TaskUser tu = new TaskUser(new TaskUserPK(taskId, userId), read, edit, delete, setPerm, complete);
            TaskAssign ta = (TaskAssign) em.createNamedQuery("TaskAssign.findByTaskIdAndDestId").setParameter("taskId", taskId).setParameter("destUserId", userId).getSingleResult();

            if (ta != null) {
                ta.setIsApproved(true);
                ta.setIsReturned(true);
            } else {
                System.out.println("TaskAssign is NULL!!!!");
            }


            // Check if there is a TaskUser entry already
            if ((em.find(TaskUser.class, new TaskUserPK(taskId, userId))) == null) {
                result = storeTaskUser(tu);
            }

            if (result) {
                result = storeTaskAssignment(ta);
            }
        } catch (DBStoringException ex) {
            Accounting.warning(TaskManagerE.class.getName(), ex.getMessage());
        } finally {
            if (result) {
                trans.commit();
            } else {
                trans.rollback();
            }
        }
        return result;
    }

    /**
     * Rejects a task
     * 
     * @param task
     * @param user
     * @return 
     */
    public boolean rejectTask(int taskId, int userId) {
        boolean result = false;
        EntityTransaction trans = em.getTransaction();
        try {
            trans.begin();
            // TODO: Figure out how to find a TaskAssignment without sourceUserID. It's hardcoded right now.
            TaskAssign ta = em.find(TaskAssign.class, new TaskAssignPK(taskId, 2, userId));
            if (ta != null) {
                ta.setIsApproved(false);
                ta.setIsReturned(true);
            }
            result = storeTaskAssignment(ta);
        } catch (DBStoringException ex) {
            Accounting.warning(TaskManagerE.class.getName(), ex.getMessage());
        } finally {
            if (result) {
                trans.commit();
            } else {
                trans.rollback();
            }
        }
        return result;
    }

    List<Task> getTasks(int userId) {
        User newUser = em.find(User.class, userId);
        List<TaskUser> tasksList = newUser.getTaskUserList();
        List<Task> tasks = new ArrayList<Task>(tasksList.size());
        for (TaskUser user : tasksList) {
            Task task = user.getTask();
            //TODO: Figure out if we need the commented out statement. It produces an error.
            //task.setGroupId(task.getGroupId());
            tasks.add(task);
        }
        return tasks;
    }

    List<Task> getPendingTasks(int userId) {
        User newUser = em.find(User.class, userId);
        List<TaskAssign> tasksList = newUser.getTaskAssignedList();
        List<Task> tasks = new ArrayList<Task>(tasksList.size());
        for (TaskAssign user : tasksList) {
            if (user.getIsReturned()) {
                Task task = user.getTask();
//                task.setGroupId(task.getGroupId());
                tasks.add(task);
            }
        }
        return tasks;
    }

    List<Task> getCompletedTasks(int userId) {
        User newUser = em.find(User.class, userId);
        List<TaskAssign> tasksList = newUser.getTaskAssignedList();
        List<Task> tasks = new ArrayList<Task>(tasksList.size());
        for (TaskAssign user : tasksList) {
            if (user.getTask().getStatus() == 2) {
                Task task = user.getTask();
//                task.setGroupId(task.getGroupId());
                tasks.add(task);
            }
        }
        return tasks;
    }
}